

    ClassMap.implement
    (
        {
            /**
             * Get a class file by its canonical name.
             * 
             * @param {String} canonicalName    A canonical class name.
             * @return {ClassFile}
             * @throws {RangeError} If the map does not contain the class file
             * @see #put
             * @see #add
             * @see #has
             * @see #contains
             */
            get: function (canonicalName) 
            {
                if (this.has(canonicalName))
                    return this.data[canonicalName];
                
                throw new RangeError ('Undefined class: ' + canonicalName);
            }
            
            /**
             * Add a class file directly to the map.
             * @param {Object} value
             * @return {void}
             * @throws {RangeError}
             * @throws {TypeError}
             * @see #put
             */
        ,   add: function (value) 
            {
                if (Object.is(value))
                    this.put(value.canonicalName, value);
            }
            
            /**
             * Put a class file into the class map.
             * @param {String} canonicalName   A canonical class name
             * @param {ClassFile} classFile    A class file
             * @return {void}
             * @throws {RangeError} If the class file has already been put
             * @throws {TypeError}  If either argument is of the incorrect type
             * @see #add
             */
        ,   put: function (canonicalName, classFile) 
            {
                if (!String.notEmpty(canonicalName))
                    throw new TypeError ('Canonical name cannot be an empty string');
                    
                if (this.has(canonicalName))
                    throw new RangeError ('Duplicate class: ' + canonicalName);
                
                if (false === ClassFile.is(classFile))    
                    throw new TypeError ('ClassFile expected, not ' + classFile);
                    
                this.data[canonicalName]= classFile;
            }
            
            /**
             * Remove a key and its corresponding class file from the class map
             * 
             * @param {ClassFile} canonicalName
             * @return {void}
             * @throws {RangeError}
             */
        ,   remove: function (canonicalName) 
            {
                if (false === this.has(canonicalName))
                    throw new RangeError 
            }
            
            /**
             * Determine if the class map stores a class file by providing it
             * a canonical class name.
             * @param {String} canonicalName
             * @return {Boolean}
             */
        ,   has: function (canonicalName) 
            {
                return String.is(canonicalName) && canonicalName in this.data;
            }
            
            /**
             * Determine if the class map contains a particular class file.
             * @param {ClassFile} classFile
             * @return {Boolean}
             */
        ,   contains: function (classFile) 
            {
                for (var accessor in this.data) 
                {
                    if (classFile === this.data[accessor])
                        return true;
                }
                
                return false;
            }
            
            /**
             * Determine if the class map is empty.
             * @return {Boolean}
             */
       ,    isEmpty: function () 
            {
               for (var accessor in this.data)
                   return false;
                   
               return true;
            }
           
            /**
             * Get the keys in use by the class map. Each key is a
             * canonical class name.
             * @return {Array.<String>}
             */
        ,   keys: function () 
            {
                var keys= [];
                for (var accessor in this.data) 
                {
                    if (this.data.hasOwnProperty(accessor))
                        keys.push(accessor);
                }
                
                return keys;
            }
            
            /**
             * Get the class files contained by the class map
             * @return {Array.<ClassFile>}
             */
        ,   values: function () 
            {
                var values= [];
                for (var accessor in this.data) 
                {
                    if (this.data.hasOwnProperty(accessor))
                    values.push(this.data[accessor]);
                }
                return values;
            }
            
            /**
             * Clear the class map of all its keys and values
             * @return {void}
             */
        ,   clear: function () 
            {
                this.data= {};
            }
        }
    );
    
    /**
     * Create a new class map. 
     * @constructor
     */
    function ClassMap () 
    {
        this.clear();
    };
